using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.Profiling;
using XLua;
using Object = System.Object;

namespace WorldMapBase.Tile.Pool
{

    [System.Serializable]
    public class ObjectPoolBase
    {
#if UNITY_EDITOR
        [DisplayOnly][BlackList]
        public string _name = "ObjectPool";     // DEBUG 池的名称，只在编辑器下生效
#endif
        
        [DisplayOnly][SerializeField]
        [Header("当前池中的元素个数")]
        protected int _count;                   
        [DisplayOnly][SerializeField]
        [Header("池外的元素个数")]
        protected int _outerCount;
        [DisplayOnly][SerializeField]
        [Header("默认容量，对应构造函数的capacity字段")]
        protected int _defaultCapacity;         
        [SerializeField]
        [Header("是否开启池自动收缩")]
        protected bool _enableAutoShrink;          
        [SerializeField]
        [Header("池中最大的闲置数量")]
        protected int _idleMaxCount;            
        [SerializeField]
        [Header("单次收缩的数量")]
        protected int _frameShrinkCount;        
        [SerializeField]
        [Header("收缩时间间隔")]
        protected float _shrinkIntervalTime;    
        [DisplayOnly][SerializeField]
        [Header("上次收缩的时间")]
        protected float _lastShrinkTime;

        public int AliveCount => _outerCount;
        public int PoolCount => _count;
        public int defaultPoolCount => _defaultCapacity;
        public int defaultInitCount;
        public int idleMaxCount => _idleMaxCount;
        public int maxPoolCount;
        public int extraCreatedCount;
        public float UsePercent;
        private bool mdestoryed = false;
        public virtual void Shrink(float time)
        {
            
        }

        public virtual void Destroy()
        {
            if (mdestoryed)
            {
                Debug.LogError("重复Destory 该对象");
            }
            mdestoryed = true;
        }
    }
    
    public abstract class ObjectPool<T> : ObjectPoolBase where T : class
    {
        protected Stack<T> _objects;

        
        protected int DefaultCapacity
        {
            get
            {
                return _defaultCapacity;
            }
        }

        protected int Count
        {
            get
            {
                return _count;
            }
        }
        
        public ObjectPool(int capacity)
        {
            _objects = new Stack<T>(capacity);
            _defaultCapacity = capacity;
            _enableAutoShrink = false;
            _idleMaxCount = Int32.MaxValue;
            _frameShrinkCount = 0;
            _shrinkIntervalTime = float.MaxValue;
            _count = 0;
            _outerCount = 0;
        }
        
//        public ObjectPool(int capacity)
//        {
//            _objects = new Stack<T>(capacity);
//            _defaultCapacity = capacity;
//            _enableAutoShrink = true;
//            _idleMaxCount = 1;
//            _frameShrinkCount = 2;
//            _shrinkIntervalTime = 0.15f;
//            _count = 0;
//            _outerCount = 0;
//        }
//        

        public ObjectPool(int capacity, bool enableAutoShrink, int idleMaxCount, int frameShrinkCount,float shrinkIntervalTime)
        {
            _objects = new Stack<T>(capacity);
            _defaultCapacity = capacity;
            _enableAutoShrink = enableAutoShrink;
            _idleMaxCount = capacity;
            _frameShrinkCount = frameShrinkCount;
            _shrinkIntervalTime = shrinkIntervalTime;
            _count = 0;
            _outerCount = 0;
        }

        public void OnInit(int initNum)
        {
//            Assert.IsTrue(initNum > 0);
            
            for (int i = 0; i < initNum; i++)
            {
                T obj = ConstructItem();
                _objects.Push(obj);
            }
            _count = initNum;
            defaultInitCount = initNum;
            extraCreatedCount = 0;
            PoolCollectionManager.GetInstance("PoolCollectionManager").AddObjectPool(this);
        }

        public void OnInitAsync(int initNum,Action callBack = null)
        {
            Assert.IsTrue(initNum > 0);
            
            for (int i = 0; i < initNum; i++)
            {
                FrameExecuteTimeMonitor.AddTask(() =>
                {
                    T obj = ConstructItem();
                    _objects.Push(obj);
                });
            }
            FrameExecuteTimeMonitor.AddTask(() =>
            {
                _count = initNum;
                defaultInitCount = initNum;
                extraCreatedCount = 0;
                PoolCollectionManager.GetInstance("PoolCollectionManager").AddObjectPool(this);
                callBack?.Invoke();
            });
        }

        protected abstract T ConstructItem();

        public int GetTotalCount()
        {
            return _count + _outerCount;
        }
        
        public T GetItem()
        {
            if (_count == 0)
            {
                _outerCount++;
#if UNITY_EDITOR
                maxPoolCount = Mathf.Max(_outerCount, maxPoolCount);
                extraCreatedCount++;
#endif
                var item = ConstructItem();
                return item;
            }

            T obj = _objects.Pop();
            OnGetObject(obj);
            _count--;
            _outerCount++;
#if UNITY_EDITOR
            maxPoolCount = Mathf.Max(_outerCount, maxPoolCount);
#endif
            return obj;
        }

        protected virtual void OnGetObject(T obj)
        {
            
        }
        
        
        public void RecoverItem(T obj)
        {
            BeforeRecover(obj);
            _objects.Push(obj);
            _count++;
            _outerCount--;
            
#if UNITY_EDITOR
            if (_count > _defaultCapacity)
            {
                if (obj is Transform)
                {
                    //UnityEngine.Debug.LogError( string.Format("{0} 默认容量不足，默认容量：{1}", (obj as Transform).name,_defaultCapacity));
                }
                else
                {
                    //UnityEngine.Debug.LogError( string.Format("{0} 默认容量不足，默认容量：{1}", obj.GetType().ToString(),_defaultCapacity));
                }
            }  
#endif
        }


        protected virtual void BeforeRecover(T obj)
        {
            
        }
        
        public override void Shrink(float currentTime)
        {
            if (!_enableAutoShrink)
            {
                return;
            }

            if (currentTime - _lastShrinkTime < _shrinkIntervalTime)
            {
                return;
            }

            if (_count <= _idleMaxCount)
            {
                return;
            }
            
            for (int i = 0; i < _frameShrinkCount; i++)
            {
                if (_count > _idleMaxCount)
                {
                    T obj = _objects.Pop();
                    _count--;
                    OnRemoveItem(obj);
                }
                else
                {
                    break;
                }
            }

            _lastShrinkTime = currentTime;
        }

        protected virtual void OnRemoveItem(T obj)
        {
            
        }
        
        
        public virtual void Destroy()
        {
            OnBeforeDestroy();

            var poolCollectionMgr = PoolCollectionManager.GetInstance("PoolCollectionManager");
            if (poolCollectionMgr)
            {
                poolCollectionMgr.RemoveObjectPool(this);
            }
            //TODO:里面元素要清理么？
            _objects.Clear();
            _objects = null;
            _count = 0;
            
            OnDestroy();
        }

        protected virtual void OnBeforeDestroy()
        {
            
        }
        
        protected virtual void OnDestroy()
        {
            
        }
        
    }
}
